﻿#nullable disable//disable 
using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Mvc.Infrastructure;

// 此处扩展的是netcore自身的方法，所以使用系统命名空间
namespace Microsoft.AspNetCore.Mvc.Rendering
{
    /// <summary>
    /// Html自定义扩展
    /// </summary>
    public static class HtmlHelperViewExtensions
    {
        #region 基础扩展
        /// <summary>
        /// 获取Action
        /// </summary>
        /// <param name="helper"></param>
        /// <param name="action"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public static IHtmlContent Action(this IHtmlHelper helper, string action, object parameters = null)
        {
            var controller = (string)helper.ViewContext.RouteData.Values["controller"];

            return Action(helper, action, controller, parameters);
        }

        /// <summary>
        /// 获取Action
        /// </summary>
        /// <param name="helper"></param>
        /// <param name="action"></param>
        /// <param name="controller"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public static IHtmlContent Action(this IHtmlHelper helper, string action, string controller, object parameters = null)
        {
            var area = (string)helper.ViewContext.RouteData.Values["area"];

            return Action(helper, action, controller, area, parameters);
        }

        /// <summary>
        /// 获取Action
        /// </summary>
        /// <param name="helper"></param>
        /// <param name="action"></param>
        /// <param name="controller"></param>
        /// <param name="area"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        public static IHtmlContent Action(this IHtmlHelper helper, string action, string controller, string area, object parameters = null)
        {
            if (action == null)
                throw new ArgumentNullException("action");

            if (controller == null)
                throw new ArgumentNullException("controller");


            var task = RenderActionAsync(helper, action, controller, area, parameters);

            return task.Result;
        }

        /// <summary>
        /// RenderActionAsync
        /// </summary>
        /// <param name="helper"></param>
        /// <param name="action"></param>
        /// <param name="controller"></param>
        /// <param name="area"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        private static async Task<IHtmlContent> RenderActionAsync(this IHtmlHelper helper, string action, string controller, string area, object parameters = null)
        {
            // fetching required services for invocation
            var serviceProvider = helper.ViewContext.HttpContext.RequestServices;
            var actionContextAccessor = helper.ViewContext.HttpContext.RequestServices.GetRequiredService<IActionContextAccessor>();
            var httpContextAccessor = helper.ViewContext.HttpContext.RequestServices.GetRequiredService<IHttpContextAccessor>();
            var actionSelector = serviceProvider.GetRequiredService<IActionSelector>();

            // creating new action invocation context
            var routeData = new RouteData();
            foreach (var router in helper.ViewContext.RouteData.Routers)
            {
                routeData.PushState(router, null, null);
            }
            routeData.PushState(null, new RouteValueDictionary(new { controller = controller, action = action, area = area }), null);
            routeData.PushState(null, new RouteValueDictionary(parameters ?? new { }), null);

            //get the actiondescriptor
            RouteContext routeContext = new RouteContext(helper.ViewContext.HttpContext) { RouteData = routeData };
            var candidates = actionSelector.SelectCandidates(routeContext);
            var actionDescriptor = actionSelector.SelectBestCandidate(routeContext, candidates);

            var originalActionContext = actionContextAccessor.ActionContext;
            var originalhttpContext = httpContextAccessor.HttpContext;
            try
            {
                var newHttpContext = serviceProvider.GetRequiredService<IHttpContextFactory>().Create(helper.ViewContext.HttpContext.Features);
                if (newHttpContext.Items.ContainsKey(typeof(IUrlHelper)))
                {
                    newHttpContext.Items.Remove(typeof(IUrlHelper));
                }
                newHttpContext.Response.Body = new MemoryStream();
                var actionContext = new ActionContext(newHttpContext, routeData, actionDescriptor);
                actionContextAccessor.ActionContext = actionContext;
                var invoker = serviceProvider.GetRequiredService<IActionInvokerFactory>().CreateInvoker(actionContext);
                await invoker.InvokeAsync();
                newHttpContext.Response.Body.Position = 0;
                using (var reader = new StreamReader(newHttpContext.Response.Body))
                {
                    return new HtmlString(reader.ReadToEnd());
                }
            }
            catch (Exception ex)
            {
                return new HtmlString(ex.Message);
            }
            finally
            {
                actionContextAccessor.ActionContext = originalActionContext;
                httpContextAccessor.HttpContext = originalhttpContext;
                if (helper.ViewContext.HttpContext.Items.ContainsKey(typeof(IUrlHelper)))
                {
                    helper.ViewContext.HttpContext.Items.Remove(typeof(IUrlHelper));
                }
            }
        }

        /// <summary>
        /// 转Json
        /// </summary>
        /// <param name="htmlHeler"></param>
        /// <param name="val"></param>
        /// <returns></returns>
        public static string ToJson(this IHtmlHelper htmlHeler, object val)
        {
            if (val != null)
            {
                return Newtonsoft.Json.JsonConvert.SerializeObject(val);
            }
            return "";
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="htmlHelper"></param>
        /// <returns></returns>
        public static string CheckFor(this IHtmlHelper htmlHelper)
        {

            return "";

        }
        #endregion

        //=====================================================================================================================

        #region 路由操作
        /// <summary>
        /// 返回区域
        /// 调用方式：@Html.area()
        /// </summary>
        /// <param name="helper">System.Web.Mvc.HtmlHelper对象，不需要传值</param>
        /// <returns></returns>
        public static HtmlString area(this IHtmlHelper helper)
        {
            return new HtmlString(helper.ViewContext.RouteData.Values["area"].ToString());
        }

        /// <summary>
        /// 返回控制器名称
        /// 调用方式：@Html.contorller()
        /// </summary>
        /// <param name="helper">System.Web.Mvc.HtmlHelper对象，不需要传值</param>
        /// <returns></returns>
        public static HtmlString contorller(this IHtmlHelper helper)
        {

            return new HtmlString(helper.ViewContext.RouteData.Values["Controller"].ToString());
        }

        /// <summary>
        /// 返回Action名称
        /// 调用方式：@Html.action()
        /// </summary>
        /// <param name="helper">System.Web.Mvc.HtmlHelper对象，不需要传值</param>
        /// <returns></returns>
        public static HtmlString action(this IHtmlHelper helper)
        {
            return new HtmlString(helper.ViewContext.RouteData.Values["Action"].ToString());
        }

        /// <summary>
        /// 返回区域和控制器 
        /// 调用方式：@Html.AC()
        /// </summary>
        /// <param name="helper">System.Web.Mvc.HtmlHelper对象，不需要传值</param>
        /// <returns></returns>
        public static HtmlString AC(this IHtmlHelper helper)
        {
            var areaName = helper.ViewContext.RouteData.Values["area"].ToString();
            var controllerName = helper.ViewContext.RouteData.Values["Controller"].ToString();

            return new HtmlString("/" + areaName + "/" + controllerName);
        }

        #endregion

        //=====================================================================================================================




        #region Radio选中项
        /// <summary>
        /// Radio选中项
        /// 调用方法：@Html.IsRadioChecked(Model.XXX.ToString(), "1")
        /// </summary>
        /// <param name="htmlHelper">System.Web.Mvc.HtmlHelper对象，不需要传值</param>
        /// <param name="Value">当前控件的值(一般是从库中读取的值)</param>
        /// <param name="CompareValue">对比值</param>
        /// <returns></returns>
        public static string IsRadioChecked(this IHtmlHelper htmlHelper, string Value, string CompareValue)
        {
            string result = "";
            if (Value == CompareValue)
            {
                result = "checked";
            }
            return result;
        }
        #endregion

        #region select控件中的Option选中
        /// <summary>
        /// select控件中的Option选中
        /// 调用方法：@Html.IsOptionSelected(Model.XXX.ToString(), "1")
        /// </summary>
        /// <param name="htmlHelper">System.Web.Mvc.HtmlHelper对象，不需要传值</param>
        /// <param name="Value">当前控件的值(一般是从库中读取的值)</param>
        /// <param name="CompareValue">对比值</param>
        /// <returns></returns>
        public static string IsOptionSelected(this IHtmlHelper htmlHelper, string Value, string CompareValue)
        {
            string result = "";
            if (Value == CompareValue)
            {
                result = "selected";
            }
            return result;
        }
        #endregion 



    }
}
